/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkRtp.h"
#include "MkUtil/MkLog.h"
#include "MkEvent/MkTimer.h"
#include "MkMedia/MkMediaUtil.h"


CMkRtp::CMkRtp(CMkTimer* pTimer, BOOL bCheckRtcp/* = FALSE*/, Uint32 RtcpCheckTime/* = 10*/)
    : m_pTimer(pTimer)
    , m_RtcpCheckTime(RtcpCheckTime)
{
    if (bCheckRtcp) {
        m_pTimer->AddTimer([this]() {
            OnRtcpCheck();
        }, RtcpCheckTime * 1000 / 2, m_RtcpCheckSession);
    }
}

Uint32 CMkRtp::AddRtpRemoter(const Uint32& Ssrc, const MkRtpRemoter& Remoter)
{
    Uint32 ErrorCode = SystemError;
    m_RemoterLock.WLock();
    MkUnorderedMap<Uint32, MkRtpRemoter>::iterator it = m_MapRemoter.find(Ssrc);
    if (it == m_MapRemoter.end()) {
        ErrorCode = NoneError;
        m_MapRemoter[Ssrc] = Remoter;
    }
    m_RemoterLock.WUnlock();
    if (MkRtpRecver & Remoter.RtpType) {
        CMkRtcpPacket RecverReportRtcp;
        RecverReportRtcp.SetPayload(MkRtcpRr);
        RecverReportRtcp.SetReceptionSsrc(Remoter.Ssrc);
        SendRtcpPacket(RecverReportRtcp, Remoter.RtpRemoteHost, Remoter.RtpRemotePort + 1);
    }
    if (MkRtpSender & Remoter.RtpType) {
        CMkRtcpPacket SenderReportRtcp;
        SenderReportRtcp.SetPayload(MkRtcpSr);
        SenderReportRtcp.SetSenderReportSsrc(Remoter.Ssrc);
        SenderReportRtcp.SetSenderReportNtpTimeStamp(NowMkTime.GetTvSec());
        SenderReportRtcp.SetSenderReportRtpTimeStamp(Remoter.TimeStamp);
        SenderReportRtcp.SetSenderReportSenderPacketCount(Remoter.SendPacketCount);
        SenderReportRtcp.SetSenderReportSenderOctetCount(0);
        SendRtcpPacket(SenderReportRtcp, Remoter.RtpRemoteHost, Remoter.RtpRemotePort + 1);
    }

    CMkRtcpPacket DescRtcp;
    DescRtcp.SetPayload(MkRtcpSdes);
    DescRtcp.SetSourceDescriptionSsrc(Remoter.Ssrc);
    DescRtcp.SetSourceDescriptionAddChunk(MkSdesName, "MkRtpServer");
    SendRtcpPacket(DescRtcp, Remoter.RtpRemoteHost, Remoter.RtpRemotePort + 1);
    return ErrorCode;
}

Uint32 CMkRtp::GetScore()
{
    //first get average recvSpeed;
    Uint32 TotalRecvSpeed = 0;
    CMkTime NowTime = NowMkTime;
    m_RemoterLock.RLock();
    MkUnorderedMap<Uint32, MkRtpRemoter>::iterator it = m_MapRemoter.begin();
    for (; it != m_MapRemoter.end(); it++) {
        TotalRecvSpeed += static_cast<Uint32>(CMkMediaUtil::GetAverageSpeed(it->second.RecvPacketCount, it->second.CreateTime));
    }
    if (0 == TotalRecvSpeed) {
        TotalRecvSpeed = m_MapRemoter.size();
    }
    m_RemoterLock.RUnlock();
    return MaxUint32 - TotalRecvSpeed;
}

Uint32 CMkRtp::DeleteRemoter(const Uint32& Ssrc)
{
    Uint32 ErrorCode = InvalidParams;
    //delete call
    if (MaxInt32 == Ssrc) {
        m_RemoterLock.WLock();
        MkUnorderedMap<Uint32, MkRtpRemoter> TmpRemoter = m_MapRemoter;
        m_MapRemoter.clear();
        m_RemoterLock.WUnlock();
        MkUnorderedMap<Uint32, MkRtpRemoter>::iterator it = TmpRemoter.begin();
        for (; it != TmpRemoter.end(); it++) {
            if (it->second.RtpClosedCb) {
                it->second.RtpClosedCb();
            }
        }
    } else {
        MkRtpRemoter Remoter;
        m_RemoterLock.WLock();
        MkUnorderedMap<Uint32, MkRtpRemoter>::iterator it = m_MapRemoter.find(Ssrc);
        if (it != m_MapRemoter.end()) {
            ErrorCode = NoneError;
            Remoter = it->second;
            m_MapRemoter.erase(it);
        }
        m_RemoterLock.WUnlock();
        if (NoneError == ErrorCode && Remoter.RtpClosedCb) {
            Remoter.RtpClosedCb();
        }
    }
    return ErrorCode;
}

Uint32 CMkRtp::GetRemoterSsrc(const MkString& RtpRemoteHost, Uint16 RtpRemotePort)
{
    Uint32 Ssrc = 0;
    m_RemoterLock.RLock();
    MkUnorderedMap<Uint32, MkRtpRemoter>::iterator it = m_MapRemoter.begin();
    for (; it != m_MapRemoter.end(); it++) {
        if (RtpRemoteHost == it->second.RtpRemoteHost
            && RtpRemotePort == it->second.RtpRemotePort) {
            Ssrc = it->first;
            break;
        }
    }
    m_RemoterLock.RUnlock();
    return Ssrc;
}

Uint32 CMkRtp::GetRemoter(const Uint32& Ssrc, MkRtpRemoter& Remoter)
{
    Uint32 ErrorCode = InvalidParams;
    m_RemoterLock.RLock();
    MkUnorderedMap<Uint32, MkRtpRemoter>::iterator it = m_MapRemoter.find(Ssrc);
    if (it != m_MapRemoter.end()) {
        Remoter = it->second;
        ErrorCode = NoneError;
    }
    m_RemoterLock.RUnlock();
    return ErrorCode;
}

Uint32 CMkRtp::GetSenderRemoter(const Uint32& Ssrc, const Uint32& TimeStamp, MkRtpRemoter& Remoter)
{
    Uint32 ErrorCode = InvalidParams;
    m_RemoterLock.RLock();
    MkUnorderedMap<Uint32, MkRtpRemoter>::iterator it = m_MapRemoter.find(Ssrc);
    if (it != m_MapRemoter.end()) {
        it->second.TimeStamp = TimeStamp;
        it->second.SeqNum++;
        Remoter = it->second;
        ErrorCode = NoneError;
    }
    m_RemoterLock.RUnlock();
    return ErrorCode;
}

Uint32 CMkRtp::GetFirstRemoter(MkRtpRemoter& Remoter)
{
    Uint32 ErrorCode = QueueEmpty;
    m_RemoterLock.RLock();
    MkUnorderedMap<Uint32, MkRtpRemoter>::iterator it = m_MapRemoter.begin();
    if (it != m_MapRemoter.end()) {
        Remoter = it->second;
        ErrorCode = NoneError;
    }
    m_RemoterLock.RUnlock();
    return ErrorCode;
}

Uint32 CMkRtp::SendData(const Uint8* pData, Uint32 nDataLen, Uint32 Ssrc, Uint32 TimeStamp)
{
    return NoneError;
}

Uint32 CMkRtp::SendBuffer(const CMkBufferList& BufList, Uint32 Ssrc, Uint32 TimeStamp)
{
    MkRtpRemoter Remoter;
    Uint32 ErrorCode = GetSenderRemoter(Ssrc, TimeStamp, Remoter);
    MkCheckErrorLog(ErrorCode, "ssrc:%x not find remoter\n", Ssrc);
    Uint16 SeqNum = Remoter.SeqNum;
    CMkRtpPacket RtpPacket;
    RtpPacket.SetSsrc(Ssrc);
    RtpPacket.SetTimeStamp(TimeStamp);
    RtpPacket.SetPayloadType(Remoter.Payload);
    RtpPacket.SetSequenceNumber(SeqNum++);

    Uint32 nOffset = 0;
    Uint32 nToGetSize = 0;
    Uint8 pRtpHeader[Len16] = { 0 };
    while (nOffset < BufList.GetTatolLen()) {
        nToGetSize = MkMin(BufList.GetTatolLen() - nOffset, MkMaxRtpLen);
        CMkBufferList ItemList;
        BufList.GetBuffer(nOffset, nToGetSize, ItemList);
        nOffset += nToGetSize;
        RtpPacket.SetMarker(nOffset == BufList.GetTatolLen());
        RtpPacket.SetPayloadBufferList(ItemList);
        RtpPacket.SetSequenceNumber(SeqNum++);
        RtpPacket.PacketHeader(pRtpHeader, Len16);
        SendRtpPacket(RtpPacket, Remoter.RtpRemoteHost, Remoter.RtpRemotePort);
    }
    return NoneError;
}

Uint32 CMkRtp::ParseRtpPacket(const CMkRtpPacket& RtpPacket, const MkString& SenderHost, const Uint16& SenderPort)
{
    Uint32 ErrorCode = UnknownError;
    MkRtpPacketCallback RtpPacketCb;
    m_RemoterLock.RLock();
    MkUnorderedMap<Uint32, MkRtpRemoter>::iterator it = m_MapRemoter.find(RtpPacket.GetSsrc());
    if (it != m_MapRemoter.end()) {
        RtpPacketCb = it->second.RtpPacketCb;
        ErrorCode = NoneError;
        if (SenderHost != it->second.RtpRemoteHost
            || SenderPort != it->second.RtpRemotePort) {
            MkWarningLog("recv rtp packet sender info not match real(%s:%d) manage(%s:%d)\n", SenderHost.c_str(), SenderPort, it->second.RtpRemoteHost.c_str(), it->second.RtpRemotePort);
        }
    }
    m_RemoterLock.RUnlock();
    if (RtpPacketCb) {
        ErrorCode = RtpPacketCb(RtpPacket, SenderHost, SenderPort);
    }
    return ErrorCode;
}

Uint32 CMkRtp::ParseRtcpPacket(const CMkRtcpPacket& RtcpPacket, const MkString& SenderHost, const Uint16& SenderPort)
{
    Uint32 ErrorCode = UnknownError;
    Uint32 Ssrc = 0;
    switch (RtcpPacket.GetPayload()) {
    case MkRtcpSr:
        Ssrc = RtcpPacket.GetSenderReportSsrc();
        break;
    case MkRtcpRr:
        Ssrc = RtcpPacket.GetReceptionSsrc();
        break;
    case MkRtcpSdes:
        Ssrc = RtcpPacket.GetSourceDescriptionSsrc();
        break;
    case MkRtcpBye:
        if (!RtcpPacket.GetByeSsrc().empty()) {
            Ssrc = *RtcpPacket.GetByeSsrc().begin();
        }
        break;
    case MkRtcpApp:
        Ssrc = RtcpPacket.GetAppSsrc();
        break;
    default:
        break;
    }

    MkRtcpPacketCallback RtcpPacketCb;
    MkRtpClosedCallback CloseCb;
    m_RemoterLock.RLock();
    MkUnorderedMap<Uint32, MkRtpRemoter>::iterator it = m_MapRemoter.find(Ssrc);
    if (it != m_MapRemoter.end()) {
        RtcpPacketCb = it->second.RtcpPacketCb;
        CloseCb = it->second.RtpClosedCb;
        it->second.LastRtcpActiveTime = NowMkTime;
        ErrorCode = NoneError;
    }
    m_RemoterLock.RUnlock();
    if (RtcpPacketCb) {
        ErrorCode = RtcpPacketCb(RtcpPacket, SenderHost, SenderPort);
    }
    if (MkRtcpBye == RtcpPacket.GetPayload()
        && CloseCb) {
        CloseCb();
    }
    return ErrorCode;
}

void CMkRtp::OnRtcpCheck()
{
    CMkTime NowTime = NowMkTime;
    MkUnorderedMap<Uint32, MkRtpRemoter> TmpMapRemoter;
    m_RemoterLock.RLock();
    TmpMapRemoter = m_MapRemoter;
    m_RemoterLock.RUnlock();
    MkUnorderedMap<Uint32, MkRtpRemoter>::iterator it = TmpMapRemoter.begin();
    for (; it != TmpMapRemoter.end(); it++) {
        if (NowTime.OffsetSec(it->second.LastRtcpActiveTime) > (int)m_RtcpCheckTime) {
            if (it->second.RtpClosedCb) {
                it->second.RtpClosedCb();
            }
        } else {
            //Send Rtcp
            if (MkRtpRecver & it->second.RtpType) {
                CMkRtcpPacket RecverReportRtcp;
                RecverReportRtcp.SetPayload(MkRtcpRr);
                RecverReportRtcp.SetReceptionSsrc(it->second.Ssrc);
                SendRtcpPacket(RecverReportRtcp, it->second.RtpRemoteHost, it->second.RtpRemotePort + 1);
            }
            if (MkRtpSender & it->second.RtpType) {
                CMkRtcpPacket SenderReportRtcp;
                SenderReportRtcp.SetPayload(MkRtcpSr);
                SenderReportRtcp.SetSenderReportSsrc(it->second.Ssrc);
                SenderReportRtcp.SetSenderReportNtpTimeStamp(NowMkTime.GetTvSec());
                SenderReportRtcp.SetSenderReportRtpTimeStamp(it->second.TimeStamp);
                SenderReportRtcp.SetSenderReportSenderPacketCount(it->second.SendPacketCount);
                SenderReportRtcp.SetSenderReportSenderOctetCount(0);
                SendRtcpPacket(SenderReportRtcp, it->second.RtpRemoteHost, it->second.RtpRemotePort + 1);
            }
        }
    }
}

CMkRtp::~CMkRtp()
{

}
